package com.niiwoo.civet.account.service.local.check;

import com.alibaba.dubbo.config.annotation.Reference;
import com.niiwoo.civet.account.dao.entity.AccountCheckingCheck;
import com.niiwoo.civet.account.dao.entity.AccountCheckingException;
import com.niiwoo.civet.account.dao.entity.AccountCheckingManage;
import com.niiwoo.civet.account.dao.entity.AccountCheckingParseTask;
import com.niiwoo.civet.account.dao.mapper.AccountCheckingCheckMapperExt;
import com.niiwoo.civet.account.dao.mapper.AccountCheckingExceptionMapperExt;
import com.niiwoo.civet.account.dao.mapper.AccountCheckingManageMapperExt;
import com.niiwoo.civet.account.dao.mapper.AccountCheckingParseTaskMapperExt;
import com.niiwoo.civet.account.dto.response.CheckFileConfirmResponseDTO;
import com.niiwoo.civet.account.service.local.check.job.api.CheckRecordService;
import com.niiwoo.civet.account.service.local.check.job.api.NotifyService;
import com.niiwoo.civet.account.service.local.check.job.enums.CheckResultEnum;
import com.niiwoo.civet.account.service.local.check.job.enums.SysCheckResultEnum;
import com.niiwoo.civet.account.service.local.check.job.enums.TaskStepEnum;
import com.niiwoo.civet.account.service.local.check.job.util.DateUtil;
import com.niiwoo.civet.user.service.SendSmsDubboService;
import com.niiwoo.tripod.consumer.component.FileUploadHandler;
import com.niiwoo.tripod.consumer.properties.FileUploadProperties;
import com.niiwoo.tripod.lanmao.component.LanMaoDownloadService;
import com.niiwoo.tripod.lanmao.properties.LanMaoProperties;
import com.niiwoo.tripod.lanmao.request.LanMaoDownloadRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

//import com.niiwoo.civet.user.service.SendSmsDubboService;

@Slf4j
@Service
@EnableConfigurationProperties({LanMaoProperties.class})
public class AccountCheckingCheckService implements CheckRecordService, NotifyService {
	
	@Autowired
	private LanMaoProperties lanMaoProperties;
	
	@Autowired
	private AccountCheckingCheckMapperExt accountCheckingCheckMapperExt;
	
	@Autowired
	private AccountCheckingManageMapperExt accountCheckingManageMapperExt;
	
	@Autowired
	private AccountCheckingExceptionMapperExt accountCheckingExceptionMapperExt;
	
	@Autowired
	private AccountCheckingParseTaskMapperExt accountCheckingParseTaskMapperExt;
	
	@Autowired
	private LanMaoDownloadService lanMaoDownloadService;
	
	@Autowired
    FileUploadHandler fileUploadHandler;
	
	@Autowired
	private AccountCheckingConfirmService accountCheckingConfirmService;
	
	@Reference(version = "1.0.0")
	private SendSmsDubboService sendSmsDubboService;

	public Long save(TaskStepEnum step, String checkDate) {
		Long recordId = findCheckRecord(checkDate);
		if (recordId != null && recordId > 0)
			return recordId;

		AccountCheckingCheck accountCheckingCheck = new AccountCheckingCheck();
		accountCheckingCheck.setBillDate(checkDate);
		accountCheckingCheck.setCheckingTime(new Date());
		accountCheckingCheck.setConfirmStatus(CheckResultEnum.UNCONFIRM.getValue()); //TODO:
		accountCheckingCheck.setSysCheckingStatus(SysCheckResultEnum.UNDOWNLOAD.getValue()); // 对账中

		accountCheckingCheckMapperExt.insertSelective(accountCheckingCheck);
		return accountCheckingCheck.getId();
	}

	public void update(TaskStepEnum step, Long recordId) {
		AccountCheckingCheck accountCheckingCheck = new AccountCheckingCheck();
		accountCheckingCheck.setId(recordId);

		switch (step) {
		case UNSTART:
		case UNDOWNLOAD:
			accountCheckingCheck.setSysCheckingStatus(SysCheckResultEnum.UNDOWNLOAD.getValue());
			break;
		case UNUPLOAD: // 未上传或上传失败
			return;
		case UNZIP: // 未解压或解压失败
			accountCheckingCheck.setSysCheckingStatus(SysCheckResultEnum.UNZIP.getValue());
			break;
		case UNSTORAGE: // 没入库或入库失败
			accountCheckingCheck.setSysCheckingStatus(SysCheckResultEnum.UNSTORAGE.getValue());
			break;
		case UNCHECK: // 未对账或对账失败
			accountCheckingCheck.setSysCheckingStatus(SysCheckResultEnum.UNCHECK.getValue());
			break;
		case UNSEND: // 未发送预警短信或者对账成功邮件
			return;
		case FAIL: // 对账完成未确认
			accountCheckingCheck.setSysCheckingStatus(SysCheckResultEnum.FAIL.getValue());
			break;
		case SUCCESS: // 已确认
			accountCheckingCheck.setSysCheckingStatus(SysCheckResultEnum.SUCCESS.getValue());
			break;
		default:
			return;
		}

		accountCheckingCheckMapperExt.updateByPrimaryKeySelective(accountCheckingCheck);
	}

	public void updateLastStepRemark(TaskStepEnum step, Long recordId, boolean isRecheck) {
		try {
			AccountCheckingCheck accountCheckingCheck = new AccountCheckingCheck();
			accountCheckingCheck.setId(recordId);
	
			switch (step) {
			case UNSTART:
				accountCheckingCheck.setRemark(TaskStepEnum.UNSTART.getDesc());
				break;
			case UNDOWNLOAD:
				accountCheckingCheck.setRemark(TaskStepEnum.UNDOWNLOAD.getDesc());
				break;
			case UNUPLOAD: // 未上传或上传失败
				accountCheckingCheck.setUploadStatus((byte) 2); //上传失败
				break;
			case UNZIP: // 未解压或解压失败
				accountCheckingCheck.setRemark(TaskStepEnum.UNZIP.getDesc());
				break;
			case UNSTORAGE: // 没入库或入库失败
				accountCheckingCheck.setRemark(TaskStepEnum.UNSTORAGE.getDesc());
				break;
			case UNCHECK: // 未对账或对账失败
				accountCheckingCheck.setRemark(TaskStepEnum.UNCHECK.getDesc());
				break;
			case UNSEND: // 未发送预警短信或者对账成功邮件
				accountCheckingCheck.setNotifyStatus((byte) 2); //通知失败
				break;
			case UNCONFIRM: //系统对账成功，调用存管对账确认接口失败
				accountCheckingCheck.setSysCheckingStatus(SysCheckResultEnum.SUCCESS.getValue()); //系统对账成功
				if (!isRecheck) {
					accountCheckingCheck.setConfirmStatus(CheckResultEnum.UNCONFIRM.getValue()); //调用存管对账确认接口失败
				} else {
					// 防止状态错位
					AccountCheckingCheck old = accountCheckingCheckMapperExt.selectByPrimaryKey(recordId);
					if (old == null || old.getConfirmStatus() != CheckResultEnum.CONFIRMED.getValue()) {
						accountCheckingCheck.setConfirmStatus(CheckResultEnum.UNCONFIRM.getValue());
					}
				}
				accountCheckingCheck.setRemark(TaskStepEnum.UNCONFIRM.getDesc());
				break;
			case FAIL: // 对账失败
				accountCheckingCheck.setRemark(TaskStepEnum.FAIL.getDesc());
				break;
			case SUCCESS: // 对账成功
				accountCheckingCheck.setRemark(TaskStepEnum.SUCCESS.getDesc());
				accountCheckingCheck.setConfirmStatus(CheckResultEnum.CONFIRMED.getValue()); //2-已确认
				accountCheckingCheck.setConfirmTime(new Date());
				accountCheckingCheck.setHandleManager("系统自动完成");
				break;
			default:
				return;
			}
	
			accountCheckingCheckMapperExt.updateByPrimaryKeySelective(accountCheckingCheck);
		} catch (Exception e) {
			log.error("update check record[{}] fail, last step[{}], {}", recordId, step.getDesc(), e.getMessage(), e);
		}
	}

	public boolean getCheckResult(Long recordId, String fileDate) {
		AccountCheckingCheck accountCheckingCheck = accountCheckingCheckMapperExt.selectByPrimaryKey(recordId);
		if (accountCheckingCheck == null) {
			log.error("check record not exists. [{}]", recordId);
			return false;
		}

		// 查询异常记录表看是否存在对应的异常记录，如果存在则返回false，不存在则返回true
		Long exceptionRecordCount = accountCheckingExceptionMapperExt.countExceptionRecord(recordId);
		return exceptionRecordCount > 0 ? false : true;
	}

	public Long findCheckRecord(Long recordId) {
		AccountCheckingCheck accountCheckingCheck = accountCheckingCheckMapperExt.selectByPrimaryKey(recordId);
		return accountCheckingCheck == null ? null : recordId;
	}

	public Long findCheckRecord(String checkDate) {
		List<AccountCheckingCheck> list = accountCheckingCheckMapperExt.selectByBillDate(checkDate);
		if (list == null || list.isEmpty())
			return null;
		return list.get(0).getId();
	}

	public TaskStepEnum findTaskStep(Long recordId) {
		AccountCheckingCheck accountCheckingCheck = accountCheckingCheckMapperExt.selectByPrimaryKey(recordId);
		if (accountCheckingCheck == null)
			return TaskStepEnum.UNSTART;

		switch (accountCheckingCheck.getSysCheckingStatus()) {
		case 1:
			return TaskStepEnum.UNDOWNLOAD;
		case 2:
			return TaskStepEnum.UNZIP;
		case 3:
			return TaskStepEnum.UNSTORAGE;
		case 4:
			return TaskStepEnum.UNCHECK;
		case 5:
			return TaskStepEnum.FAIL;
		case 6:
			return TaskStepEnum.SUCCESS;
		default:
			return TaskStepEnum.UNSTART;
		}
	}
	
	public boolean checkParseTask(String checkType, String checkDate) {
		List<AccountCheckingParseTask> list = accountCheckingParseTaskMapperExt
				.selectByCheckDate(checkType, checkDate);
		
		if (list != null && !list.isEmpty()) {
			AccountCheckingParseTask task = list.get(0);
			return task.getStatus() == 1 ? true : false;
		}
		
		return false;
	}

	public void saveParseTask(String checkType, String checkDate, boolean isSuccess) {
		List<AccountCheckingParseTask> list = accountCheckingParseTaskMapperExt
				.selectByCheckDate(checkType, checkDate);
		
		if (list != null && !list.isEmpty()) {
			AccountCheckingParseTask task = list.get(0);
			task.setStatus(isSuccess ? (byte) 1 : (byte) 2);
			accountCheckingParseTaskMapperExt.updateByPrimaryKeySelective(task);
		} else {
			AccountCheckingParseTask task = new AccountCheckingParseTask();
			task.setCheckDate(checkDate);
			task.setCreateTime(new Date());
			task.setStatus(isSuccess ? (byte) 1 : (byte) 2);
			task.setCheckType(checkType);
			accountCheckingParseTaskMapperExt.insertSelective(task);
		}
	}

	public void batchSaveCheckException(List<Object> list) {
		if (list == null) return;
		
		for (Object obj : list) {
			accountCheckingExceptionMapperExt.insertSelective((AccountCheckingException) obj);
		}
		
//		accountCheckingExceptionMapperExt.batchInsert(list);
	}
	
	public void deleteAllCheckException(Long checkRecordId) {
		if (checkRecordId == null) return;
		
		accountCheckingExceptionMapperExt.deleteAllCheckException(checkRecordId);
	}

	public void notify(Long recordId, String fileDate) {
		try {
			// 暂时不通知，等短信和邮件服务稳定之后再处理
			List<AccountCheckingManage> list = accountCheckingManageMapperExt.seleteAllActiveManager();
			if (list == null || list.isEmpty()) {
				log.info("handle manager not exists.");
				return;
			}
			
			//TODO: 通知 
			// 失败 短信通知
			for (AccountCheckingManage manage : list) {
				//当前没有短信通知模板
				sendSmsDubboService.sendSmsByMobile(manage.getMobile(), "【"+fileDate+"】系统对账失败，请尽快安排人工核对处理，否则影响银行提现出款~");
			}
				
			// 成功 邮件通知
			AccountCheckingCheck accountCheckingCheck = new AccountCheckingCheck();
			accountCheckingCheck.setId(recordId);
			accountCheckingCheck.setNotifyStatus((byte) 1); //通知成功
			accountCheckingCheckMapperExt.updateByPrimaryKeySelective(accountCheckingCheck);

			log.info("notify success.");
		} catch (Exception e) {
			log.error("notify check manager failure, {}", e.getMessage(), e);
		}
	}

	public String uploadCheckFile(String checkFilePath, Long recordId) {
		String downloadUrl = null;
		InputStream is = null;
		try {
			// 上传checkfile
			File file = new File(checkFilePath);
			if (!file.exists()) return null;
			
			is = new FileInputStream(file);
			byte[] buf = new byte[(int) file.length()];
			is.read(buf);
			
			FileUploadProperties.FileUploadResult uploadResult = fileUploadHandler.upload(buf, false, "zip");
			
			downloadUrl = uploadResult.getImageUrl();
			
			AccountCheckingCheck accountCheckingCheck = new AccountCheckingCheck();
			accountCheckingCheck.setId(recordId);
			accountCheckingCheck.setDownloadUrl(downloadUrl);
			accountCheckingCheck.setUploadStatus((byte) 1);
			accountCheckingCheckMapperExt.updateByPrimaryKeySelective(accountCheckingCheck);
			
		} catch (Exception e) {
			log.error("upload checkfile failure, checkRecordId[{}] {}", recordId, e.getMessage(), e);
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
				}
			}
		}
		return downloadUrl;
	}

	public void downloadCheckFile(boolean fromBankApi, Long checkRecordId, String targetZipPath, String checkDate) throws Exception {
		String downloadUrl = null;
		
		if (!fromBankApi) {
			AccountCheckingCheck accountCheckingCheck = accountCheckingCheckMapperExt.selectByPrimaryKey(checkRecordId);
			if (accountCheckingCheck == null) {
				fromBankApi = true;
			} else {
				downloadUrl = accountCheckingCheck.getDownloadUrl();
				
				if (downloadUrl == null || "".equals(downloadUrl)) fromBankApi = true;
			}
		} 
		
		if (fromBankApi) { 
			// 从存管银行下载，下载并重命名
			LanMaoDownloadRequest request = new LanMaoDownloadRequest();
			request.setFileDate(DateUtil.parseCheckDate(checkDate));
			request.setPlatformNo(lanMaoProperties.getPlatformNo());
			
			CompletableFuture<File> future = lanMaoDownloadService.download(request, targetZipPath);
			
			try {
				future.get();
			} catch (Exception e) {
				throw e;
			}
		} else { 
			//TODO: 从文件服务器下载
			
		}
	}

	@Override
	public void afterCheck(String checkDate, Long checkRecordId) throws Exception {
		// 对账后置事件

		AccountCheckingCheck accountCheckingCheck = accountCheckingCheckMapperExt.selectByPrimaryKey(checkRecordId);
		
		if (accountCheckingCheck != null && accountCheckingCheck.getConfirmStatus() == CheckResultEnum.CONFIRMED.getValue()) { //2-已确认
			log.info("has confirmed. [{}]", checkRecordId);
		} else {
			// 调用银行对账确认接口
			CheckFileConfirmResponseDTO result = accountCheckingConfirmService.checkFileConfirmForFileDate(checkDate);
			
			if (result.getStatus() == null || "false".equals(result.getStatus())) {
				throw new Exception("call bank confirm api failure. ["+checkRecordId+"]");
			}
		}
	}

	@Override
	public int countExceptionRecordForHandleType(Long checkRecordId){
		Set<Integer> handleTypeSet = new HashSet<>();
		handleTypeSet.add(1);
		handleTypeSet.add(2);
		handleTypeSet.add(3);
		int countExceptionRecord = accountCheckingExceptionMapperExt.countExceptionRecordLevel(checkRecordId,handleTypeSet);
	    return countExceptionRecord;
	}
}
